package com.block.product.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.block.account.enums.AccountTypeEnum;
import com.block.account.enums.ActionTypeEnum;
import com.block.account.model.dto.ChangeAmountDTO;
import com.block.account.service.IAccountHandleService;
import com.block.common.constant.AppRspCodeConstant;
import com.block.common.constant.RedisKeyConstant;
import com.block.common.enums.ChargeTypeEnum;
import com.block.common.exception.NotifyExceptionService;
import com.block.common.service.IChannelCommonService;
import com.block.common.util.LocalDateUtil;
import com.block.common.vo.ResponseVo;
import com.block.db.entity.*;
import com.block.db.mapper.ProductProfitUvInfoMapper;
import com.block.product.model.dto.ProductClickDTO;
import com.block.product.service.IProductBaseInfoService;
import com.block.product.service.IProductOnlieInfoService;
import com.block.product.service.IProductProfitInfoService;
import com.block.product.service.IProductProfitUvInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 产品收益uv统计信息 服务实现类
 * </p>
 *
 * @author 
 * @since 2023-09-04
 */
@Service
public class ProductProfitUvInfoServiceImpl extends ServiceImpl<ProductProfitUvInfoMapper, ProductProfitUvInfo> implements IProductProfitUvInfoService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    IProductBaseInfoService productBaseInfoService;
    @Autowired
    IProductProfitInfoService productProfitInfoService;
    @Autowired
    IProductOnlieInfoService productOnlieInfoService;
    @Autowired
    NotifyExceptionService notifyExceptionService;
    @Autowired
    IChannelCommonService channelCommonService;
    @Autowired
    IAccountHandleService accountHandleService;

    @Override
    public ResponseVo countProductClick(ProductClickDTO productClickDTO, ChannelBaseInfo channelBaseInfo, ApplicationInfo applicationInfo) {

        Long remainSecond = LocalDateUtil.getRemainSecondNumber();
        String redisKey = StrUtil.format(RedisKeyConstant.PRODUCT_UV_RECORD_KEY, productClickDTO.getProductId(), productClickDTO.getReqIp());
        boolean result = stringRedisTemplate.opsForValue()
                .setIfAbsent(redisKey, System.currentTimeMillis()+"",remainSecond, TimeUnit.SECONDS);

        if (!result){
            // 加锁失败
            return new ResponseVo(AppRspCodeConstant.SUCCESS);
        }

        try {

            // 产品上架信息
            ProductOnlieInfo productOnlieInfo = productOnlieInfoService.getById(productClickDTO.getProductId());
            String nowDate = LocalDate.now().toString();
            // 产品的有效uv 统计

            productClickDTO.setDateInfo(nowDate);

            // 1.记录产品uv记录
            this.recordProfitUvInfo(productOnlieInfo, channelBaseInfo, applicationInfo, productClickDTO);

            ProductBaseInfo productBaseInfo = productBaseInfoService.getProductInfoById(productOnlieInfo.getProductId());
            if (ObjectUtil.equals(productBaseInfo.getChargeType(), ChargeTypeEnum.UV.getValue()) ||
                    ObjectUtil.equals(productBaseInfo.getChargeType(), ChargeTypeEnum.REG.getValue())){
                // 统计uv或者注册产品的点击
                // 2.统计
                productProfitInfoService.recordProductProfitInfo(productOnlieInfo.getProductId(), productOnlieInfo,productBaseInfo, nowDate, channelBaseInfo.getChannelCode());
            }

            // 修改账户余额
            changeAccountAmount(productOnlieInfo);

            return new ResponseVo(AppRspCodeConstant.SUCCESS);
        }catch (Exception exception){
            exception.printStackTrace();
            String content = StrUtil.format("统计异常:channelCode:{};productId:{}", channelBaseInfo.getChannelCode(), productClickDTO.getProductId());
            notifyExceptionService.notifyNoticeInfo("PRODUCT", "产品uv统计", content, exception);
        }
        return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION);
    }

    private void recordProfitUvInfo(ProductOnlieInfo productOnlieInfo, ChannelBaseInfo channelBaseInfo, ApplicationInfo applicationInfo, ProductClickDTO productClickDTO) {
        ProductProfitUvInfo productProfitUvInfo = new ProductProfitUvInfo();
        productProfitUvInfo.setUid(productClickDTO.getUid());
        productProfitUvInfo.setProductId(productOnlieInfo.getProductId());
        productProfitUvInfo.setProductName(productOnlieInfo.getProductName());
        productProfitUvInfo.setDateInfo(productClickDTO.getDateInfo());
        productProfitUvInfo.setAppCode(applicationInfo.getAppCode());
        productProfitUvInfo.setAppName(applicationInfo.getAppName());
        productProfitUvInfo.setChannelCode(channelBaseInfo.getChannelCode());
        productProfitUvInfo.setChannelName(channelBaseInfo.getChannelName());
        productProfitUvInfo.setReqIp(productClickDTO.getReqIp());
        productProfitUvInfo.setRandomId(productClickDTO.getRandomId());

        try {
            UserAgent userAgent = UserAgentUtil.parse(productClickDTO.getUserAgent());
            productProfitUvInfo.setBrowserName(userAgent.getBrowser().getName());
            productProfitUvInfo.setPlatformName(userAgent.getPlatform().getName());
        }catch (Exception exception){
            exception.printStackTrace();
        }

        this.save(productProfitUvInfo);
    }

    @Override
    public void changeAccountAmount(ProductOnlieInfo productOnlieInfo){

        ChangeAmountDTO changeAmountDTO = new ChangeAmountDTO();
        changeAmountDTO.setChangeAmount(BigDecimal.ZERO.subtract(productOnlieInfo.getPriceAmount()));
        changeAmountDTO.setAccountId(productOnlieInfo.getProductId());
        changeAmountDTO.setAccountTypeEnum(AccountTypeEnum.PRODUCT);
        changeAmountDTO.setBillDateInfo(LocalDate.now().toString());
        changeAmountDTO.setActionTypeEnum(ActionTypeEnum.XH);
        changeAmountDTO.setOperatorId("0");
        changeAmountDTO.setOperatorName("system");

        accountHandleService.changeAmountHandle(changeAmountDTO);
    }

}
